﻿using System;
using Tiscs.Practices.Diagnostics;

namespace Tiscs.Practices
{
    /// <summary>
    /// 递归方法生成类。
    /// </summary>
    public static class Recursion
    {
        /// <summary>
        /// 无参数有返回值递归方法生成器。
        /// </summary>
        /// <typeparam name="TResult">方法返回值类型。</typeparam>
        /// <param name="f">递归运算描述方法。</param>
        /// <returns>生成器生成递归方法。</returns>
        public static Func<TResult> RFunc<TResult>(Func<Func<TResult>, TResult> f)
        {
            Exception exception;
            if (!Validation.Parameter<Func<Func<TResult>, TResult>>(nameof(f)).AssertNotNull().CheckRules(f, out exception))
            {
                throw exception;
            }
            return () => f(RFunc(f));
        }

        /// <summary>
        /// 单参数有返回值递归方法生成器。
        /// </summary>
        /// <typeparam name="T">单参数方法参数类型。</typeparam>
        /// <typeparam name="TResult">方法返回值类型。</typeparam>
        /// <param name="f">递归运算描述方法。</param>
        /// <returns>生成器生成递归方法。</returns>
        public static Func<T, TResult> RFunc<T, TResult>(Func<Func<T, TResult>, T, TResult> f)
        {
            Exception exception;
            if (!Validation.Parameter<Func<Func<T, TResult>, T, TResult>>(nameof(f)).AssertNotNull().CheckRules(f, out exception))
            {
                throw exception;
            }
            return x => f(RFunc(f), x);
        }

        /// <summary>
        /// 二参数有返回值递归方法生成器。
        /// </summary>
        /// <typeparam name="T1">第一个参数的类型。</typeparam>
        /// <typeparam name="T2">第二个参数的类型。</typeparam>
        /// <typeparam name="TResult">方法返回值类型。</typeparam>
        /// <param name="f">递归运算描述方法。</param>
        /// <returns>生成器生成递归方法。</returns>
        public static Func<T1, T2, TResult> RFunc<T1, T2, TResult>(Func<Func<T1, T2, TResult>, T1, T2, TResult> f)
        {
            Exception exception;
            if (!Validation.Parameter<Func<Func<T1, T2, TResult>, T1, T2, TResult>>(nameof(f)).AssertNotNull().CheckRules(f, out exception))
            {
                throw exception;
            }
            return (x, y) => f(RFunc(f), x, y);
        }

        /// <summary>
        /// 无参数无返回值递归方法生成器。
        /// </summary>
        /// <param name="a">递归运算描述方法。</param>
        /// <returns>生成器生成递归方法。</returns>
        public static Action RAction(Action<Action> a)
        {
            Exception exception;
            if (!Validation.Parameter<Action<Action>>(nameof(a)).AssertNotNull().CheckRules(a, out exception))
            {
                throw exception;
            }
            return () => a(RAction(a));
        }

        /// <summary>
        /// 单参数无返回值递归方法生成器。
        /// </summary>
        /// <typeparam name="T">单参数方法参数类型。</typeparam>
        /// <param name="a">递归运算描述方法。</param>
        /// <returns>生成器生成递归方法。</returns>
        public static Action<T> RAction<T>(Action<Action<T>, T> a)
        {
            Exception exception;
            if (!Validation.Parameter<Action<Action<T>, T>>(nameof(a)).AssertNotNull().CheckRules(a, out exception))
            {
                throw exception;
            }
            return x => a(RAction(a), x);
        }

        /// <summary>
        /// 二参数无返回值递归方法生成器。
        /// </summary>
        /// <typeparam name="T1">第一个参数的类型。</typeparam>
        /// <typeparam name="T2">第二个参数的类型。</typeparam>
        /// <param name="a">递归运算描述方法。</param>
        /// <returns>生成器生成递归方法。</returns>
        public static Action<T1, T2> RAction<T1, T2>(Action<Action<T1, T2>, T1, T2> a)
        {
            Exception exception;
            if (!Validation.Parameter<Action<Action<T1, T2>, T1, T2>>(nameof(a)).AssertNotNull().CheckRules(a, out exception))
            {
                throw exception;
            }
            return (x, y) => a(RAction(a), x, y);
        }
    }
}

